package courier

import (
	"bufio"
	"bytes"
	"fmt"
	"gitee.com/dongmingchao/decent-ft/src/caretaker"
	resourcePool "gitee.com/dongmingchao/decent-ft/src/resource-pool"
	"gitee.com/dongmingchao/decent-ft/src/utils"
	"log"
	"net"
	"strings"
)

func searchPassJumps(reader *bufio.Reader, jumpCount byte, dest bytes.Buffer) {
	for i := byte(0); i < jumpCount; i++ {
		s, err := reader.ReadString(0)
		if err != nil {
			log.Fatalln("refer jumps error")
		}
		dest.WriteString(s)
	}
}

func searchBack(
	originNei *resourcePool.GNeighbor,
	srcNei *resourcePool.GNeighbor,
	originAddr utils.UDPAddr,
	jumpCount byte,
	reader *bufio.Reader,
	data bytes.Buffer,
) {
	if originNei == nil {
		// 源头邻居未连接
		var ret []byte
		//if utils.IsSameLanNet(originAddr) {
		fmt.Println("try to connect origin", originAddr.String())
		ret = ConnectNeighbor(originAddr.UDPAddr)
		//}
		if ret == nil {
			// 连接失败，直接连接不可能，直接Pass发送，TODO: 以后改为间接连接
			fmt.Println("connect failed, pass response")
			jumps := make([]string, 0)
			for i := byte(0); i < jumpCount; i++ {
				s, err := reader.ReadString(0)
				if err != nil {
					log.Fatalln("refer jumps error")
				}
				jumps = append(jumps, strings.TrimRight(s, string(0)))
			}
			fmt.Println("search pass jumps:", jumps)
			originNei = &resourcePool.GNeighbor{
				DivePass:   jumps,
				RemoteAddr: srcNei.RemoteAddr,
				Bypass:     srcNei.Bypass,
			}
		} else {
			// 连接成功，取最新连接的邻居作为源
			fmt.Println("connect successful")
			neis := caretaker.GlobalStash.Neighbors
			originNei = &neis[len(neis)-1]
		}
	}
	BridgeLocalCall(*originNei, func(conn net.Conn) []byte {
		var sent bytes.Buffer
		fmt.Println("BridgeLocalCall data size", data.Len())
		//fmt.Println("BridgeLocalCall data content", data.Bytes())
		sent.WriteByte(byte(data.Len()))
		data.WriteTo(&sent)
		return sent.Bytes()
	})
}

func getSrcNeighborInBridges(rAddr utils.UDPAddr) (*resourcePool.GNeighbor, []resourcePool.GNeighbor) {
	var srcNei *resourcePool.GNeighbor
	otherNeighbors := make([]resourcePool.GNeighbor, 0)
	fmt.Println("Search Last Source Neighbor In Bridges use Addr", rAddr.String())

	for i, neighbor := range caretaker.GlobalStash.Neighbors {
		if neighbor.BridgeAddr != nil && neighbor.BridgeAddr.Equal(rAddr) {
			fmt.Println("jump Addr", neighbor.RemoteAddr.String())
			srcNei = &caretaker.GlobalStash.Neighbors[i]
			fmt.Println("parse after found", srcNei.RemoteAddr)
		} else {
			otherNeighbors = append(otherNeighbors, neighbor)
		}
	}
	return srcNei, otherNeighbors
}

func getSrcNeighbor(rAddr utils.UDPAddr, hasAsked []int) (*int, []resourcePool.GNeighbor) {
	var retI *int
	otherNeighbors := make([]resourcePool.GNeighbor, 0)
	fmt.Println("Search Last Source Neighbor use Addr", rAddr.String())

	for i, neighbor := range caretaker.GlobalStash.Neighbors {
		if neighbor.RemoteAddr.Equal(rAddr) {
			fmt.Println("jump Addr", neighbor.RemoteAddr.String())
			retI = &i
		} else {
			if utils.Contains(hasAsked, i) == false {
				otherNeighbors = append(otherNeighbors, neighbor)
			}
		}
	}
	return retI, otherNeighbors
}
